package com.base.cn.platform.os.service;

import com.base.cn.platform.os.common.constants.CommonConstants;
import com.base.cn.platform.os.common.filter.RequestData;
import com.base.cn.platform.os.common.utils.web.WebUtils;
import feign.*;
import feign.auth.BasicAuthRequestInterceptor;
import feign.codec.Encoder;
import feign.form.spring.SpringFormEncoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * 授权配置
 * <p>所有的服务接口都设置security安全验证，如果得不到security的用户和密码，</p>
 * <p>那所有的feign系统相相互调用则失败，因此要加上security的用户和密码获取配置</p>
 * @author s.li
 * @create 2018-03-01 10:26
 */
@Configuration
public class FeignAuthConfig implements RequestInterceptor{
    @Autowired
    private Environment environment;
    @Autowired
    private ObjectFactory<HttpMessageConverters> messageConverters;
    @Bean
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor(){
        String securityUserName = environment.getProperty("securityUserName");
        String securityPassword = environment.getProperty("securityPassword");
        return new BasicAuthRequestInterceptor(securityUserName,securityPassword);
    }

    @Override
    public void apply(RequestTemplate requestTemplate) {
        RequestData requestData = RequestData.requestDataThreadLocal.get();
        if(requestData != null){
            String ip = WebUtils.getIpAddr(requestData);
            StringBuilder sinCookieValue = new StringBuilder();
            sinCookieValue.append(CommonConstants.ADMIN_LOGIN_COOKIE).append("=").append( WebUtils.getCookie(requestData,CommonConstants.ADMIN_LOGIN_COOKIE));
            StringBuilder msidCookieValue = new StringBuilder();
            msidCookieValue.append(CommonConstants.MOBILE_USER_SINGLE_ID).append("=").append( WebUtils.getCookie(requestData,CommonConstants.MOBILE_USER_SINGLE_ID));
            StringBuilder sidCookieValue = new StringBuilder();
            sidCookieValue.append(CommonConstants.USER_SINGLE_ID).append("=").append( WebUtils.getCookie(requestData,CommonConstants.USER_SINGLE_ID));
            setHeaderData(requestTemplate,
                    requestData.getRequestURI(),
                    requestData.getHeaderMap().get("Referer"),
                    ip,
                    sinCookieValue,
                    msidCookieValue,
                    sidCookieValue);
        }else{
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
            if(requestAttributes !=null){
                HttpServletRequest request = requestAttributes.getRequest();
                StringBuilder sinCookieValue = new StringBuilder();
                sinCookieValue.append(CommonConstants.ADMIN_LOGIN_COOKIE).append("=").append( WebUtils.getCookie(request,CommonConstants.ADMIN_LOGIN_COOKIE));
                StringBuilder msidCookieValue = new StringBuilder();
                msidCookieValue.append(CommonConstants.MOBILE_USER_SINGLE_ID).append("=").append( WebUtils.getCookie(request,CommonConstants.MOBILE_USER_SINGLE_ID));
                StringBuilder sidCookieValue = new StringBuilder();
                sidCookieValue.append(CommonConstants.USER_SINGLE_ID).append("=").append( WebUtils.getCookie(request,CommonConstants.USER_SINGLE_ID));
                setHeaderData(requestTemplate,
                        request.getRequestURI(),
                        request.getHeader("Referer"),
                        WebUtils.getIpAddr(request),
                        sinCookieValue,
                        msidCookieValue,
                        sidCookieValue);
            }
        }
    }

    /**
     * 设置头部数据
     * @param requestTemplate
     * @param requestURI
     * @param Referer
     * @param ip
     * @param sinCookieValue
     * @param msidCookieValue
     * @param sidCookieValue
     */
    private void setHeaderData(RequestTemplate requestTemplate,
                               String requestURI,
                               String Referer,
                               String ip,
                               StringBuilder sinCookieValue,
                               StringBuilder msidCookieValue,
                               StringBuilder sidCookieValue){
        requestTemplate.header("sourceUrl", requestURI);
        requestTemplate.header("Referer", Referer);
        requestTemplate.header("x-forwarded-for", ip);
        requestTemplate.header("Proxy-Client-IP", ip);
        requestTemplate.header("WL-Proxy-Client-IP", ip);

        //把后台登录的Cookie传递过去
        requestTemplate.header("Cookie", sinCookieValue.toString(),msidCookieValue.toString(),sidCookieValue.toString());
    }

    @Bean
    public Encoder encoder(){
        return new SpringFormEncoder(new SpringEncoder(messageConverters));
    }

    /***
     * feign取消重试
     */
    @Bean
    Retryer feignRetryer() {
        return Retryer.NEVER_RETRY;
    }

    /**
     * feign请求超时设置
     * @param env
     * @return
     */
    @Bean
    Request.Options requestOptions(ConfigurableEnvironment env){
        //ribbon.ReadTimeout 6000(http读取响应socket超时时间)
        int ribbonReadTimeout = env.getProperty("ribbon.ReadTimeout", int.class, 6000);
        //3000(http建立socket超时时间)
        int ribbonConnectionTimeout = env.getProperty("ribbon.ConnectTimeout", int.class, 3000);

        return new Request.Options(ribbonConnectionTimeout, ribbonReadTimeout);
    }

    /**
     * ribbon针对http的readTimeout和connectTimeCount直接用配置
     * ribbon.ReadTimeout和ribbon.ConnectTimeout是无效的。
     * @return RestTemplate
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        HttpComponentsClientHttpRequestFactory httpRequestFactory =  new HttpComponentsClientHttpRequestFactory();
        httpRequestFactory.setReadTimeout(5000);
        httpRequestFactory.setConnectTimeout(5000);
        return new RestTemplate(httpRequestFactory);
    }
}
